<?php

/**
 * +------ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER * ---------+
 * +----------------------------------------------------------------------------+
 * | PHPKiisf - Keep It in Simple Framework					|
 * | Version 1.0								|
 * | Copyright (C) <2013>  Mario Cezzare <mcezzare@gmail.com>			|
 * | Blog: http://mcezzare.blogspot.com.br					|
 * |										|
 * | This program is part of PHPKiisf, and is free software: you can		|
 * | redistribute it and/or modify it under the terms of the GNU 		|
 * | General Public License as published by					|
 * | the Free Software Foundation, either version 3 of the License, or		|
 * | (at your option) any later version.					|					|
 * |										|									|
 * | This program is distributed in the hope that it will be useful,		|
 * | but WITHOUT ANY WARRANTY; without even the implied warranty of		|
 * | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the		|
 * | GNU General Public License for more details.				|
 * | You should have received a copy of the GNU General Public License		|
 * | along with this program.  If not, see <http://www.gnu.org/licenses/>.	|
 * +----------------------------------------------------------------------------+
 * | Author : <Mario Cezzare Angelicola Chiodi> <mcezzare@gmail.com>		|
 * +----------------------------------------------------------------------------+
 * | Contributors								|
 * |										|
 * +----------------------------------------------------------------------------+
 *
 */
/**
 * @package	Lib
 * @access	public
 * @since	2013-03-08
 * @author	Mario Cezzare <mcezzare@gmail.com>
 */

/**
 * Classe responsável por chamar o controller de acordo com
 * a solicitação Get/Post<br />
 * Resumo Limita o que vem depois do / em 2 elementos sem o 0 xxx.com/a/b/c?879=0980
 * ficando a e b , sendo :<br />
 * a=rota para controller<br />
 * b= nome publico (na url) do metodo<br />
 * c = parâmetro opcional<br />
 * o Resto tanto via get ou post são parametros automáticos do dispatcher
 */
class dispatcher extends default_controller {

	public static $_info = array() ;
	public static $_active_route ;
	private $_version = 2.0 ;
	private $_routes ;
	private $_util ;
	private $_sufix_controller ;
	private $_class_args = array() ;
	private $_last_route ;
	public $_return_not_found ;
	public $_errors ;
	public $_post_values ;
	public $_get_values ;

	function __construct( $class_args = array() ) {


		self::$_info = $_SERVER ;
		self::$_active_route = null ;

		$this->_routes = array() ;
		$this->_util = new utils() ;
		$this->_sufix_controller = ".class.php" ;
		$this->_return_not_found = true ;
		$this->_PREFIX_DEBUG_MESSAGE = sprintf( "\n[%s] - " , ucfirst( get_class( $this ) ) ) ;
		$this->_errors = array() ;
		$this->_post_values = $_POST ;
		$this->_get_values = $_GET ;
	}

	/**
	 * Função obrigatória para o autoloader
	 */
	public static function init() {

	}

	/**
	 * Adiciona uma rota ao dispatcher
	 *
	 * @param array $route	array(method,prefix,controller:function)
	 */
	public function add_route( $route ) {
		if ( is_array( $route ) ) {
			$this->_routes[] = $route ;
		}
	}

	/**
	 * Invoca o controller
	 *
	 *
	 * @global type $debug
	 * @return boolean false se não achar a rota se a variavel privada $_return_not_found = true
	 * @throws Exception
	 *
	 * @author [Mario Cezzare Angelicola Chiodi] <mcezzare@gmail.com>
	 * @since
	 */
	public function exec() {
		//sort the array to read in order
		ksort( $this->_routes ) ;

		global $debug ;
		$debug === true ? display_user_message( sprintf( "0 - %s" . var_dump( $_SERVER["REQUEST_URI"] ) , $this->_PREFIX_DEBUG_MESSAGE ) ) : null ;
		/*
		 * Filter fetches, curl, rsync ,  delete
		 */
		$query_string = explode( "&" , $_SERVER["QUERY_STRING"] ) ;
		if ( !array_key_exists( self::$_info["REQUEST_METHOD"] , array(
				"GET" => true ,
				"POST" => true ,
				"PUT" => true ,
				)
			)
		) {
			throw new Exception( "HTTP_METHOD_NOT_ALLOWED" , 2 ) ;
			return false ;
		}

		/*  Para as ações sem parâmetros */
		$controller_name = "home_controller" ;
		$default_controller = $controller_name . $this->_sufix_controller ;
		$controller_method = "display_index" ;


		/*
		 *  1º Se for a Home objects Array ( [0] => GET [1] => /? [2] => home_controller:display_index )
		 */
		$uri_work = str_replace( "?debug=true" , "" , self::$_info["REQUEST_URI"] ) ;

		if ( ( self::$_info["REQUEST_URI"] == "/" || $uri_work == "/" ) ||
			(!is_array( explode( "/" , $_SERVER["REQUEST_URI"] ) )
			)
		) {
			//include default section
			require_once CONTROLLER_DIR . $default_controller ;
			$object = new $controller_name ;
			self::$_active_route = "/" ;
			$object->$controller_method( array( "msg" => "called from line " . __LINE__ . " by " . __FILE__ ) ) ;
			return true ;
		}

		/**
		 * Se não for a Home, continua excutando,   Separa  a URL por barras
		 * Pega apenas o 1º(rota) e 2º(metodo) pedaços /rota/metodo/metodo?param=x
		 */
		$debug === true ? display_user_message( sprintf( "1 - %s" . utils::show_object( $_SERVER["REQUEST_URI"] , __LINE__ , __FILE__ ) , $this->_PREFIX_DEBUG_MESSAGE ) ) : null ;
		$request_uri = array_slice(
			array_filter(
				explode( "/" , str_replace( "?" . $_SERVER["QUERY_STRING"] , "" , $uri_work ) )
			)
			, 0 , 3 ) ;
		$debug === true ? display_user_message( utils::show_object( $request_uri , __LINE__ , __FILE__ ) ) : null ;
		$debug === true ? display_user_message( sprintf( "2 - %s" . utils::show_object( $request_uri , __LINE__ , __FILE__ ) , $this->_PREFIX_DEBUG_MESSAGE ) ) : null ;
		$debug === true ? display_user_message( sprintf( "3 - %s request_uri[] size :  %     s" , $this->_PREFIX_DEBUG_MESSAGE , count( $request_uri ) ) ) : null ;

		if ( ( is_array( $request_uri ) ) && (count( $request_uri ) > 0) ) {

			//only 3 possibilities
			if ( count( $request_uri ) == 3 ) {
//								echo "Aqui ==3<br>" ;
				$route = sprintf( "%s/%s/%s" , $request_uri[0] , $request_uri[1] , $request_uri[2] ) ;
				$public_method = null ;
				$pattern = "/(" . str_replace( "/" , "\\/" , str_replace( "?" , "^" , $route ) ) . "\/$)/" ;
			} elseif ( count( $request_uri ) == 2 ) {
//								echo "Aqui ==2 <br>" ;
				$route = sprintf( "%s/%s" , $request_uri[0] , $request_uri[1] ) ;
				$public_method = null ;
				$pattern = "/(" . str_replace( "/" , "\\/" , str_replace( "?" , "^" , $route ) ) . "\/$)/" ;
			} elseif ( count( $request_uri ) == 1 ) {
//								echo "Aqui ==1 <br>";
				$route = $request_uri[0] ;
				$public_method = null ;
				$pattern = "/(" . str_replace( "/" , "\\/" , str_replace( "?" , "^" , $route ) ) . "\/$)/" ;
			} else {
				//if the logic is right never enter here
//								echo "Aqui ==0 <br>" ;
			}
			$debug === true ? display_user_message( sprintf( "<h4>route: %s , public_method: %s , pattern: %s </h4><hr> " , $route , $public_method , $pattern ) ) : null ;
			$index_route = 0 ;

			/**
			 * Start read all routes sorted
			 */
			foreach ( $this->_routes as $key => $desired_route ) {
				$debug === true ? display_user_message( sprintf( "5 - %s %s : %s <br> \n" , $this->_PREFIX_DEBUG_MESSAGE , $key , utils::show_object( $desired_route , __LINE__ , __FILE__ ) ) ) : null ;
				/**
				 * Look for the method on defined route
				 */
				if ( preg_match( $pattern , $desired_route[1] ) ) {

					$debug === true ? printf( "<b>achei: %s , method to use: %s</b>" , $desired_route[1] , $desired_route[2] ) : null ;

					$action = explode( ":" , $desired_route[2] ) ;
//										var_dump( $action ) ;
					$controller_name = $action[0] ;
					$public_method = $action[1] ;


					require_once CONTROLLER_DIR . $controller_name . $this->_sufix_controller ;
					$object = new $controller_name ;
					/**
					 *  Garantee that dispatcher does not accept wrong function calls
					 */
//										var_dump( method_exists( $object , $public_method ) ) ;
					if ( method_exists( $object , $public_method ) ) {
						self::$_active_route = $route ;
						$object->$public_method( array(
							"dispatcher_msg" => "called from line " . __LINE__ . " by " . __FILE__ ,
							// remove position 0 that is always null and split params from postion 3 to the right
							"url_param" => array_filter( array_diff( explode( "/" , $_SERVER["REQUEST_URI"] ) , $request_uri ) ) ,
							"post" => $_POST ,
							"query_string" => $_SERVER["QUERY_STRING"] ,
							"active_route" => self::$_active_route ,
							"controller" => $controller_name ,
							"method" => $public_method ,
							)
						) ;
						return true ;
					} else {
						/**
						 * S
						 */
						array_push( $this->_errors , sprintf( " %s Method don't exists: %s" , $this->_PREFIX_DEBUG_MESSAGE , $public_method ) ) ;
//												display_message( sprintf( " %s Method don't exists: %s" , $this->_PREFIX_DEBUG_MESSAGE , $public_method ) ) ;
						continue ;
					}
				}
			}
			$index_route++ ;

			if ( count( $this->_errors ) > 0 ) {
				$message = new message() ;
				$message->msg_type = "ERROR" ;
				$message->msg_operation = "CALL INEXISTENT METHOD on->" . get_called_class() ;
				$message->msg_detail = utils::array_to_params( array_unique( $this->_errors ) ) ;
				utils::inform_user( $message ) ;
				return false ;
			}
		}
//				}

		if ( $this->_return_not_found ) {

//			throw new Exception( "..." , 404 , error_get_last() ) ;
			return false ;
		}

		$debug === true ? print "<br> Else-->" . print_r( $request_uri ) : null ;
		// include class file
		require_once CONTROLLER_DIR . $default_controller ;
		//create object
		$object = new $controller_name ;
		self::$_active_route = "/" ;
		//call method
		$object->$controller_method( array( "msg" => "from line 176" ) ) ;

		return true ;
	}

}

?>